package com.nintendo.bubblechat.netty;

import com.nintendo.bubblechat.SpringUtil;
import com.nintendo.bubblechat.entity.pojo.GroupChatMsg;
import com.nintendo.bubblechat.entity.vo.UsersVo;
import com.nintendo.bubblechat.service.FriendRequestService;
import com.nintendo.bubblechat.service.UsersService;
import com.nintendo.bubblechat.utils.JsonUtils;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.concurrent.GlobalEventExecutor;
import net.minidev.json.JSONUtil;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.List;

public class ChatHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
    //用于记录和管理所有客户端的channel
    public static ChannelGroup users = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    /**
     * 当客户端连接服务端之后 (打开连接)
     * 获取客户端的channel 并且放到ChannelGroup中去进行管理
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        users.add(ctx.channel());
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        // 当触发handlerRemoved ChannelGroup会自动移除对应的客户端channel
        String channelId =  ctx.channel().id().asShortText();
        System.out.println("客户端被移除:"+channelId);
        users.remove(ctx.channel());
        System.out.println("长id: " + ctx.channel().id().asLongText());
        System.out.println("短id: " + ctx.channel().id().asShortText());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        // 发生异常之后 关闭channel 随后从ChannelGroup中移除
        ctx.channel().close();
        users.remove(ctx.channel());
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg)
            throws Exception {
        // 获取客户端传输过来的消息
        String content = msg.text();
        System.out.println(msg.text());
        Channel currentChannel = ctx.channel();
        // 1. 获取客户端发来的消息
        DataContent dataContent = JsonUtils.jsonToPojo(content, DataContent.class);
        Integer action = dataContent.getAction();
        // 2. 判断消息类型根据不同的类型来处理不同的业务
        if (action == 1) {
            System.out.println("第一次连接");
            //2.1 当websocket第一次open的时候 初始化channel 把用户的channel和userId关联起来
            String senderId = dataContent.getChatMsg().getSenderId();
            UserChannelRel.put(senderId, currentChannel);
            // 测试
            for (Channel c : users){
                System.out.println("用户id: " + c.id().asLongText());
            }
            UserChannelRel.output();
        }else if (action == 2){
            System.out.println("action===>"+dataContent.getChatMsg());
            //2.2 聊天类型的消息 把聊天记录保存到数据库 同时标记消息的签收状态[未签收]
            ChatMsg chatMsg = dataContent.getChatMsg();
            String msgText = chatMsg.getMsg();
            String receiverId = chatMsg.getReceiverId();
            String senderId = chatMsg.getSenderId();
            if(dataContent.getIsGroupMessage()){
                System.out.println("是群聊消息");
                String groupId = dataContent.getGroupId();
                FriendRequestService friendRequestService  = (FriendRequestService) SpringUtil.getBean("friendRequestServiceImpl");
                List<UsersVo> groupMembers = friendRequestService.getGroupMembers(groupId);
                GroupChatMsg groupChatMsg = new GroupChatMsg();
                groupChatMsg.setGroupId(groupId);
                groupChatMsg.setSendUserId(senderId);
                groupChatMsg.setMsg(msgText);
                // 保存群组聊天记录到数据库
                String groupMsgId = friendRequestService.saveGroupChatMsg(groupChatMsg);
                chatMsg.setMsgId(groupMsgId);
                DataContent dataContentMsg = new DataContent();
                dataContentMsg.setChatMsg(chatMsg);
                dataContentMsg.setIsGroupMessage(true);
                dataContentMsg.setGroupId(groupId);
                for (UsersVo usersVo : groupMembers){
                    // 发送消息  从全局用户channel关系中获取接收方的channel
                    Channel receiverChannel =  UserChannelRel.get(usersVo.getId());
                    if(receiverChannel == null){
                        // TODO channel为空代表用户离线 推送消息(JPush 个推 小米推送)
                        System.out.println("群聊用户离线");
                    }else {
                        // 当receiverChannel不为空 从ChannelGroup去查找对应的channel是否存在
                        Channel findChannel = users.find(receiverChannel.id());
                        // 不发给自己
                        if(findChannel != null&& findChannel.id().asLongText().equals(receiverChannel.id().asLongText())){
                            // 用户在线
                            System.out.println("群聊用户在线：");
                            receiverChannel.writeAndFlush(new TextWebSocketFrame(JsonUtils.objectToJson(dataContentMsg)));
                        }else{
                            // TODO 用户离线
                            System.out.println("群聊用户离开");
                        }
                    }
                }
            }else{
                System.out.println("不是群聊消息");
                // 保存消息到数据库并且标记为未签收
                UsersService userService = (UsersService) SpringUtil.getBean("usersServiceImpl");
                String msgId = userService.saveMsg(chatMsg);
                chatMsg.setMsgId(msgId);
                DataContent dataContentMsg = new DataContent();
                dataContentMsg.setChatMsg(chatMsg);
                // 发送消息  从全局用户channel关系中获取接收方的channel
                System.out.println("receiverIdreceiverIdreceiverId=>"+receiverId);
                Channel receiverChannel =  UserChannelRel.get(receiverId);
                if(receiverChannel == null){
                    // TODO channel为空代表用户离线 推送消息(JPush 个推 小米推送)
                    System.out.println("用户离线");
                }else {
                    // 当receiverChannel不为空 从ChannelGroup去查找对应的channel是否存在
                    Channel findChannel = users.find(receiverChannel.id());
                    System.out.println("findChannel======>"+findChannel);
                    if(findChannel != null){
                        // 用户在线
                        System.out.println("用户在线：");
                        receiverChannel.writeAndFlush(new TextWebSocketFrame(JsonUtils.objectToJson(dataContentMsg)));
                    }else{
                        // TODO 用户离线
                        System.out.println("findChannel为空用户离开");
                    }
                }
            }

        }
        else if (action == 3){
            //2.3 签收消息类型 针对具体的消息进行签收 修改数据库中对应消息的签收状态[已签收]
            UsersService userService = (UsersService) SpringUtil.getBean("usersServiceImpl");
            // 扩展字段在signed类型的消息中 代表需要去签收的消息 id 逗号间隔
            String msgIdsStr = dataContent.getExtand();

            String msgIds[] = msgIdsStr.split(",");
            List<String> msgIdList = new ArrayList<>();
            for (String mid : msgIds){
                if(StringUtils.isNotBlank(mid)){
                    msgIdList.add(mid);
                }
            }
            System.out.println(msgIdList.toString());
            if(msgIdList!=null&&!msgIdList.isEmpty()&&msgIdList.size()>0){
                // 批量签收
                userService.updateMsgSigned(msgIdList);
            }
        }
        else if (action == 4){
            //2.4 心跳类型的消息
            System.out.println("收到来自channel为["+currentChannel+"]的心跳包...");
        }

//        System.out.println("接收到的数据: "+content);
//
//        for (Channel channel : users){
//            channel.writeAndFlush(new TextWebSocketFrame("[服务器在:]"+ LocalDateTime.now()+"接收到消息"+","+"消息为:"+content));
//        }
        // 下面这个方法 和 上边的for循环一致
//        clients.writeAndFlush(new TextWebSocketFrame("[服务器在:]"+ LocalDateTime.now()+"接收到消息"+","+"消息为:"+content));


    }
}
